package com.arcvideo.acsconnect.ui;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import android.util.Log;
import android.view.Display;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import com.arcvideo.acsconnect.app.GlobalConstant;
import com.arcvideo.acsconnect.app.SettingDataCenter;
import com.arcvideo.acsconnect.bean.MessageBean;
import com.arcvideo.acsconnect.eventbus.DialingEvent;
import com.arcvideo.acsconnect.helper.MessageHelper;
import com.arcvideo.acsconnect.rest.model.UserBean;
import com.arcvideo.acsconnect.ui.presenter.LivePresenter;
import com.arcvideo.acsconnect.ui.screen.Screen;
import com.arcvideo.acsconnect.ui.view.LiveView;
import com.arcvideo.acsconnect.widget.DialingLayout;
import com.arcvideo.acsconnect.widget.UserHeadInfoLayout;
import com.arcvideo.acsconnect.widget.UserSelectDialog;
import com.arcvideo.arcrtcsdk.ArcRtcSDK;
import com.arcvideo.arcrtcsdk.bean.AudioInfo;
import com.arcvideo.arcrtcsdk.bean.VideoInfo;
import com.arcvideo.rtccamera.Camera;
import com.arcvideo.rtccamera.CameraFactory;
import com.arcvideo.rtccamera.CameraFactoryImpl;
import com.arcvideo.arcrtcsdk.enums.SessionEventType;
import com.arcvideo.arcrtcsdk.enums.VideoProfile;
import com.arcvideo.arcrtcsdk.listener.ArcRtcListener;
import com.arcvideo.arcrtcsdk.listener.ArcRtcMessageListener;
import com.arcvideo.arcrtcsdk.utils.ScreenUtil;
import com.arcvideo.commondef.ArcTypes;
import com.arcvideo.commondef.ArcVFrame;
import com.arcvideo.commondef.CameraTypes;
import com.arcvideo.rtcmessage.model.ExtInfo;
import com.arcvideo.rtcmessage.model.RtcMemberModel;
import com.arcvideo.rtcmessage.utils.LogUtil;
import com.arcvideo.tyingyitonginhouse.R;
import com.framework.core.mvp.TitlePresenterActivity;
import com.framework.core.utils.AppUtil;
import com.framework.core.utils.ToastUtil;
import com.google.gson.Gson;

import org.greenrobot.eventbus.EventBus;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import butterknife.BindView;
import rx.Observable;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.schedulers.Schedulers;

/**
 * @author shenmengchao
 * @version 1.0.0
 * @date 2017/10/17
 * @description
 */

public class LiveActivity extends TitlePresenterActivity<LivePresenter> implements LiveView,
        ArcRtcMessageListener, View.OnFocusChangeListener {

    public final static String TAG = LiveActivity.class.getSimpleName();

    public final static String RTC_CLIENT_LIST = "rtc_client_list";
    public final static String ENTER_TYPE_CREATE = "enter_type_create";
    public final static String ENTER_TYPE_JOIN = "enter_type_join";
    public final static String ENTER_TYPE = "enter_type";
    public final static String SESSION_ID = "session_id";
    public final static String JUMP_TO_FEEDBACK = "jump_to_feedback";
    public final static String WARN_MESSAGE = "warn_message";
    public final static String TO_ACCOUNT = "to_account";
    public final static String TO_AVATAR = "to_avatar";
    public final static String TO_NAME = "to_name";

    public final static int REQUEST_CODE = 3;

    @BindView(R.id.surfaceView1)
    SurfaceView mSurfaceView1;
    @BindView(R.id.surfaceView4)
    SurfaceView mSurfaceView4;
    @BindView(R.id.surfaceView2)
    SurfaceView mSurfaceView2;
    @BindView(R.id.surfaceView3)
    SurfaceView mSurfaceView3;
    @BindView(R.id.iv_voice)
    ImageView mIvVoice;
    @BindView(R.id.rl_root)
    RelativeLayout mRlRoot;
    @BindView(R.id.uhil_1)
    UserHeadInfoLayout mUhil1;
    @BindView(R.id.uhil_2)
    UserHeadInfoLayout mUhil2;
    @BindView(R.id.uhil_3)
    UserHeadInfoLayout mUhil3;
    @BindView(R.id.uhil_4)
    UserHeadInfoLayout mUhil4;
    @BindView(R.id.ll_bottom)
    LinearLayout mLlBottom;
    @BindView(R.id.iv_hang_up)
    ImageView mIvHangUp;
    @BindView(R.id.iv_family)
    ImageView mIvFamily;
    @BindView(R.id.dialing_layout)
    DialingLayout mDialingLayout;

    LivePresenter mLivePresenter = new LivePresenter();

    private UserSelectDialog mUserSelectDialog;

    private List<SurfaceView> mSurfaceViewList = new ArrayList<>();
    private List<UserHeadInfoLayout> mUserHeadInfoLayoutList = new ArrayList<>();


    private int mSourceType = ArcTypes.ARC_SOURCETYPE_USBCAMERA;
    private ArcRtcSDK mArcRtcSdk;
    private Camera mCamera;

    private boolean mIsVoiceMute = false;
    private String mEnterType;
    private int mSessionId;

    private String mToAccount = "";
    private String mToAvatar = "";
    private String mToName = "";
    private Subscription mSubscription;

    public static void launchJoin(Activity activity, int sessionId) {
        Intent intent = new Intent(activity, LiveActivity.class);
        intent.putExtra(ENTER_TYPE, ENTER_TYPE_JOIN);
        intent.putExtra(SESSION_ID, sessionId);
        activity.startActivityForResult(intent, REQUEST_CODE);
    }

    public static void launchCreate(Activity activity, String toAccount,
                                    String toAvatar, String toName) {
        Intent intent = new Intent(activity, LiveActivity.class);
        intent.putExtra(ENTER_TYPE, ENTER_TYPE_CREATE);
        intent.putExtra(TO_ACCOUNT, toAccount);
        intent.putExtra(TO_AVATAR, toAvatar);
        intent.putExtra(TO_NAME, toName);
        activity.startActivityForResult(intent, REQUEST_CODE);
    }

    @Override
    public void initActivity(View view) {
        super.initActivity(view);
        showContent();
        dismissToolbar();
        LogUtil.d(TAG, "LiveActivity initActivity() " + this);
        initLaunchValue();
        initArcRtcSDK();
        initCamera();
        initView();
        initEvent();
        init();
    }

    /**
     * init extra value from other activity or component
     */
    private void initLaunchValue() {
        if (TextUtils.isEmpty(mEnterType)) {
            mEnterType = getIntent().getStringExtra(ENTER_TYPE);
        }
        mSessionId = getIntent().getIntExtra(SESSION_ID, 0);
        mToAccount = getIntent().getStringExtra(TO_ACCOUNT);
        mToAvatar = getIntent().getStringExtra(TO_AVATAR);
        mToName = getIntent().getStringExtra(TO_NAME);
        LogUtil.d(TAG,
                "mEnterType = " + mEnterType
                        + "mSessionId = " + mSessionId
                        + "mToAccount = " + mToAccount
                        + "mToAvatar = " + mToAvatar
                        + "mToName = " + mToName
        );
    }

    private void initArcRtcSDK() {
        if (null == mArcRtcSdk) {
            mArcRtcSdk = ArcRtcSDK.create(this);
        }
        mArcRtcSdk
                .setVideoInfo(buildVideoInfo())
                .setAudioInfo(buildAudioInfo())
                .setSurfaceViewList(buildSurfaceViewList())
                .setRtcListener(new ArcRtcListener() {
                    @Override
                    public void onSession(SessionEventType type, String userId) {
                        doOnSessionEvent(type, userId);
                    }

                    @Override
                    public void onRecVideoData(String userId) {
                        doOnFirstFrame(userId);
                    }

                    @Override
                    public void onInfo(int code, String message) {
                        doOnInfo(code, message);
                    }

                    @Override
                    public void onError(int mainCode, int subCode, String message) {
                        doOnError(mainCode, subCode, message);
                    }
                }).prepare();
    }

    private VideoInfo buildVideoInfo() {
        int fps = SettingDataCenter.getInstance().getFps();
        int encoderVideoBitrate = SettingDataCenter.getInstance().getCodeRate() * 1000;
        VideoInfo videoInfo = new VideoInfo();
        videoInfo.setBitrate(encoderVideoBitrate);
        videoInfo.setFps(fps);
        videoInfo.setVideoProfile(VideoProfile.RTC_VIDEO_PROFILE_LANDSCAPE_720P);
        return videoInfo;
    }

    private AudioInfo buildAudioInfo() {
        AudioInfo audioInfo = new AudioInfo();
        int audioType = CameraTypes.RECORD_CODEC_TYPE_OPUS;
        audioInfo.setDwAudioType(audioType);
        audioInfo.setDwSamplingRate(48000);
        return audioInfo;
    }

    private List<SurfaceView> buildSurfaceViewList() {
        mSurfaceViewList.add(mSurfaceView1);
        mSurfaceViewList.add(mSurfaceView2);
        mSurfaceViewList.add(mSurfaceView3);
        mSurfaceViewList.add(mSurfaceView4);
        return mSurfaceViewList;
    }

    private void initCamera() {
        CameraFactory factory = new CameraFactoryImpl();
        mCamera = factory.makeCamera(mSourceType, this);
        mCamera.setOnCameraDataCallback(new Camera.OnCameraDataCallback() {
            @Override
            public void onFrame(ArcVFrame frame) {
                mArcRtcSdk.sendVideoFrame(frame);
            }
        });
        mCamera.setOnErrorListener(new Camera.OnErrorListener() {
            @Override
            public void onError(int code, String message) {
                ToastUtil.showToast(message + "(" + code + ")");
                finish();
            }
        });
        mCamera.setOnInfoListener(new Camera.OnInfoListener() {
            @Override
            public void onInfo(int code, String message) {
                ToastUtil.showToast(message + "(" + code + ")");
            }
        });
    }


    private void initView() {
        mSurfaceView1.setVisibility(View.VISIBLE);
        mSurfaceView2.setVisibility(View.GONE);
        mSurfaceView3.setVisibility(View.GONE);
        mSurfaceView4.setVisibility(View.GONE);
    }


    /**
     * init event like onClickListener onFocusChangeListener and so on
     */
    private void initEvent() {
        mIvVoice.setOnFocusChangeListener(this);
        mIvHangUp.setOnFocusChangeListener(this);
        mIvFamily.setOnFocusChangeListener(this);
        mDialingLayout.setOnFocusChangeListener(this);
        mSurfaceView1.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
                mCamera.openPreview(ScreenUtil.getCameraOrientation(display));
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
                mCamera.setCameraDisplayOrientation(ScreenUtil.getCameraOrientation(display));
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                mCamera.release();
            }
        });
    }

    private void init() {
        mIvVoice.requestFocus();
        mUserHeadInfoLayoutList.add(mUhil1);
        mUserHeadInfoLayoutList.add(mUhil2);
        mUserHeadInfoLayoutList.add(mUhil3);
        mUserHeadInfoLayoutList.add(mUhil4);
        if (mEnterType.equals(ENTER_TYPE_CREATE)) {
            mDialingLayout.show();
            mDialingLayout.setOnDialingListener(new DialingLayout.OnDialingListener() {
                @Override
                public void onHangUp() {
                    finish();
                }

                @Override
                public void onTimeout() {
                    ToastUtil.showToast("对方无应答");
                    finish();
                }
            });
            mDialingLayout.setUserInfo(mToAvatar, mToName);
            mLlBottom.setVisibility(View.GONE);
        } else {
            mDialingLayout.dismiss();
            mLlBottom.setVisibility(View.VISIBLE);
        }

        if (mEnterType.equals(ENTER_TYPE_CREATE)) {
            mArcRtcSdk.createAndJoinSession(false);
        } else if (mEnterType.equals(ENTER_TYPE_JOIN)) {
            mArcRtcSdk.joinSession(mSessionId);
        }
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (null != mArcRtcSdk) {
            mArcRtcSdk.setArcRtcMessageListener(this);
        }
        mCamera.open();
    }

    @Override
    public int inflateContentView() {
        return R.layout.activity_live;
    }

    @Override
    public boolean isFullScreen() {
        return true;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mCamera.release();
        if (null != mSubscription) {
            mSubscription.unsubscribe();
        }
        mArcRtcSdk.leaveSession();
        mArcRtcSdk.releaseArcRtcEngine();
        //关闭LiveActivity,需要发消息给DialingEvent,停止拨号音
        EventBus.getDefault().post(new DialingEvent());
    }

    @Override
    public LivePresenter getPresenter() {
        return mLivePresenter;
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_PAGE_DOWN:     //向上翻页键
            case KeyEvent.KEYCODE_MEDIA_NEXT:
                Log.d(TAG, "page down--->");
                break;
            case KeyEvent.KEYCODE_PAGE_UP:     //向下翻页键
            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
                Log.d(TAG, "page up--->");
                break;
            case KeyEvent.KEYCODE_ENTER:     //确定键enter
            case KeyEvent.KEYCODE_DPAD_CENTER:
                Log.d(TAG, "enter--->");
                if (mDialingLayout.isShown()) {
                    //如果接听中页面显示，点击确定按钮，都是关闭当前页面
                    MessageHelper.sendHangUpMessage(mToAccount, mSessionId + "");
                    finish();
                    return super.onKeyDown(keyCode, event);
                }
                if (mIvFamily.hasFocus()) {
                    mLivePresenter.getAccountsByPage(this);
                    return super.onKeyDown(keyCode, event);
                }
                if (mIvHangUp.hasFocus()) {
                    finish();
                    return super.onKeyDown(keyCode, event);
                }
                if (mIvVoice.hasFocus()) {
                    mIsVoiceMute = !mIsVoiceMute;
                    refreshVoiceStatus();
                    return super.onKeyDown(keyCode, event);
                }
                break;
            case KeyEvent.KEYCODE_BACK:
                Log.d(TAG, "back--->");
                if (mDialingLayout.isShown()) {
                    //在通话页面，点击back按钮，如果拨打页面正在显示，需要发消息给被邀请方
                    MessageHelper.sendHangUpMessage(mToAccount, mSessionId + "");
                }
                finish();
                break;
            default:
                break;
        }

        return super.onKeyDown(keyCode, event);
    }

    private void refreshVoiceStatus() {
        refreshVoiceIcon();
        mArcRtcSdk.enableAudioMute(mIsVoiceMute);
    }

    private void refreshVoiceIcon() {
        if (mIsVoiceMute) {
            if (mIvVoice.hasFocus()) {
                mIvVoice.setImageResource(R.mipmap.ic_microphone_disable_checked);
            } else {
                mIvVoice.setImageResource(R.mipmap.ic_microphone_disable);
            }
        } else {
            if (mIvVoice.hasFocus()) {
                mIvVoice.setImageResource(R.mipmap.ic_microphone_checked);
            } else {
                mIvVoice.setImageResource(R.mipmap.ic_microphone);
            }
        }
    }

    private void doOnSessionEvent(SessionEventType type, String userId) {
        switch (type) {
            case CREATE:
                mSessionId = mArcRtcSdk.getSessionInfoList().get(0).getSessionid();
                refreshLayout();
                refreshVoiceStatus();
                sendInviteMessage(mToAccount, true);
                break;
            case JOIN:
                refreshLayout();
                refreshVoiceStatus();
                break;
            case REC_JOIN:
                refreshLayout();
                if (mArcRtcSdk.getSessionInfoList().size() == 2
                        && View.GONE == mLlBottom.getVisibility()) {
                    //邀请成功，第一人加入成功后，需要关闭拨号页面
                    mDialingLayout.dismiss();
                    mLlBottom.setVisibility(View.VISIBLE);
                }
                if (null != mSubscription) {
                    mSubscription.unsubscribe();
                }
                break;
            case REC_LEFT:
                refreshLayout();
                if (mArcRtcSdk.getSessionInfoList().size() == 1) {
                    //倒数第二人退出房间,延迟60s后，如果没人加入就自动退出
                    mSubscription = Observable
                            .interval(1, TimeUnit.SECONDS)
                            .subscribeOn(Schedulers.io())
                            .observeOn(AndroidSchedulers.mainThread())
                            .subscribe(new Action1<Long>() {
                                @Override
                                public void call(Long aLong) {
                                    if (aLong > GlobalConstant.AUTO_HANG_UP_TIMEOUT) {
                                        ToastUtil.showToast("通话已结束，自动挂断");
                                        mSubscription.unsubscribe();
                                        finish();
                                    }
                                }
                            });
                }
                break;
            default:
                break;
        }
    }

    /**
     * when yourself join in session
     * when yourself create session
     * when somebody join in or left session
     * you need to refresh surfaceView's width height topMargin and leftMargin
     */
    private void refreshLayout() {
        refreshUserHeadInfoData();
        int onlineMember = getOnlineNumber();
        Screen.create(this, onlineMember, mSurfaceViewList, mUserHeadInfoLayoutList).refresh();
    }

    private int getOnlineNumber() {
        if (null != mArcRtcSdk) {
            return mArcRtcSdk.getSessionInfoList().size();
        }
        return 0;
    }

    private void refreshUserHeadInfoData() {
        //有可能在Activity OnDestroy之后，收到有人离开的回调，这时候sessionInfoList = null，会导致crash
        //所以需要做非空判断
        if(null == mArcRtcSdk){
            return;
        }
        List<RtcMemberModel> sessionInfoList = mArcRtcSdk.getSessionInfoList();
        if (null == sessionInfoList) {
            return;
        }
        for (int i = 0; i < sessionInfoList.size(); i++) {
            ExtInfo extInfo = new Gson().fromJson(sessionInfoList.get(i).getExtinfo(), ExtInfo.class);
            if (null != extInfo) {
                mUserHeadInfoLayoutList.get(i).setAvatar(extInfo.getIconurl());
                mUserHeadInfoLayoutList.get(i).setNickname(extInfo.getNickname());
                mUserHeadInfoLayoutList.get(i).setVisibility(View.GONE);
            }
        }
    }


    private void doOnFirstFrame(String cid) {
        LogUtil.d("LiveActivity doOnFirstFrame cid:%s", cid);
    }


    private void doOnInfo(int code, String message) {
        LogUtil.d(TAG, "doOnInfo() code:" + code + ", message:" + message);
    }

    private void doOnError(int mainCode, int subCode, String message) {
        LogUtil.dFormat("LiveActivity doOnError mainCode:%s, subCode=%s, message:%s",
                mainCode, subCode, message);
        ToastUtil.showLongToast(message);
        finish();
    }

    @Override
    public void getUserListSuccess(List<UserBean> list) {
        showUserSelectDialog(list);
    }

    private void showUserSelectDialog(List<UserBean> list) {
        if (null == mUserSelectDialog) {
            mUserSelectDialog = new UserSelectDialog(this, list);
            mUserSelectDialog.setOnItemClickListener(new UserSelectDialog.OnItemClickListener() {
                @Override
                public void onItemClick(String userId) {
                    int currentOnlineSize = mArcRtcSdk.getSessionInfoList().size();
                    if (isUserInSession(userId)) {
                        ToastUtil.showLongToast("被邀请对象已经在通话中，无法邀请");
                        return;
                    }
                    if (currentOnlineSize >= GlobalConstant.MAX_SESSION_LENGTH) {
                        ToastUtil.showLongToast("当前房间人数已满，无法继续邀请");
                        return;
                    }
                    sendInviteMessage(userId, false);

                }
            });
        } else {
            mUserSelectDialog.setData(list);
        }
        mUserSelectDialog.show();
    }

    private boolean isUserInSession(String userId) {
        List<RtcMemberModel> list = mArcRtcSdk.getSessionInfoList();
        for (RtcMemberModel rtcMemberModel : list) {
            if (rtcMemberModel.getUserid().equals(userId)) {
                return true;
            }
        }
        return false;
    }

    private void sendInviteMessage(String toAccount, boolean isFirstInvite) {
        int res = MessageHelper.sendInviteMessage(toAccount, mSessionId + "");
        if (0 == res) {
            ToastUtil.showToast("邀请成功");
        } else {
            if (isFirstInvite) {
                finish();
            }
            ToastUtil.showToast("邀请失败，该用户不在线");
        }
    }

    @Override
    public void onMessage(int code, String extInfo, String msg) {
        MessageBean messageBean = new Gson().fromJson(msg, MessageBean.class);
        if (MessageBean.MSG_TYPE_REPLY.equals(messageBean.getMsgtype())) {
            if (!messageBean.isResultAccept()) {
                ToastUtil.showToast(messageBean.getNickname() + "拒绝加入通话");
                if (messageBean.getId().equals(mToAccount)) {
                    //如果是当前邀请的护士拒绝了通话请求，就直接关闭页面
                    finish();
                }
            } else {
                ToastUtil.showToast(messageBean.getNickname() + "同意加入通话");
            }
        } else if (MessageBean.MSG_TYPE_INVITE.equals(messageBean.getMsgtype())) {
            MessageHelper.sendReplyMessage(messageBean.getId(), MessageBean.RESULT_REJECT, mSessionId + "");
        }
    }

    @Override
    public void onStatusChange(String cid, int status, String extInfo) {
        ExtInfo connectInfo = new Gson().fromJson(extInfo, ExtInfo.class);
        if (null != mUserSelectDialog) {
            mUserSelectDialog.updateData(connectInfo.getUserid(), status + "");
        }
    }

    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        switch (v.getId()) {
            case R.id.iv_voice:
                refreshVoiceIcon();
                break;
            case R.id.iv_hang_up:
                mIvHangUp.setImageResource(hasFocus ? R.mipmap.ic_hangup_checked : R.mipmap.ic_hangup);
                break;
            case R.id.iv_family:
                mIvFamily.setImageResource(hasFocus ? R.mipmap.ic_add_user_checked : R.mipmap.ic_add_user);
                break;
            case R.id.dialing_layout:
                break;
            default:
                break;
        }
    }
}
